package pl.edu.mimuw.irs.rcp.wizard;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.FileEditorInput;

import pl.edu.mimuw.irs.core.model.design.net.IRSPlace;
import pl.edu.mimuw.irs.core.model.design.net.IRSWorkflow;
import pl.edu.mimuw.irs.core.model.design.net.refinement.Refinement;
import pl.edu.mimuw.irs.core.model.design.resource.Resources;
import pl.edu.mimuw.irs.core.model.design.resource.Roles;
import pl.edu.mimuw.irs.rcp.controller.editor.bucket.Bucket;
import pl.edu.mimuw.irs.rcp.controller.layout.StructuralLayout;
import pl.edu.mimuw.irs.rcp.persistence.IPersistence;
import pl.edu.mimuw.irs.rcp.persistence.PersistenceAdapter;
import pl.edu.mimuw.irs.rcp.persistence.bucket.BucketPersistence;
import pl.edu.mimuw.irs.rcp.persistence.resource.ResourcesPersistence;
import pl.edu.mimuw.irs.rcp.util.Logger;
import pl.edu.mimuw.irs.rcp.util.MessageCode;
import pl.edu.mimuw.irs.rcp.util.UITexts;
import pl.edu.mimuw.irs.rcp.wizard.newproject.ProjectModel;
import pl.edu.mimuw.irs.rcp.wizard.newproject.ProjectPage;

public class NewProjectWizard extends Wizard implements INewWizard {
	
	// *** Attributes

	//private IWorkbench workbench;
	//private IStructuredSelection selection;
	private ProjectPage projectPage;
	//private ResourcesPage resourcesPage;
	private ProjectModel newProjectModel;
	public ProjectModel getNewProjectModel() {
		return newProjectModel;
	}

	// *** Methods
	
	@Override
	public void init(IWorkbench workbench, IStructuredSelection selection) {
		this.newProjectModel = new ProjectModel();
		//this.workbench = workbench;
		//this.selection = selection;
		
		this.setWindowTitle(UITexts.get(MessageCode.PROJECT_WIZARD_NAME));
	}
	
	@Override
	public IWizardPage getStartingPage() {
		return projectPage;
	}
	
	@Override
	public void addPages() {
		 projectPage = new ProjectPage();
	     addPage(projectPage);
		 //resourcesPage = new ResourcesPage();
	     //addPage(resourcesPage);
	}
	
	@Override
	public boolean canFinish() {
		return projectPage.isPageComplete();
	}
	
	
	
	@Override
	public boolean performFinish()  {

		/* Preparing resources. */
		
		InputStream workflowSource = createWorkflowAsStream();
		InputStream rolesSource = createRolesAsStream();
		InputStream resourcesSource = createResourcesAsStream();
		InputStream bucketSource = createBucketAsStream();
		IProject project = createProject();
		if (workflowSource == null || resourcesSource == null || 
				rolesSource == null || project == null) return false;
		
		IFile workflowFile = null;
		IFile resourcesFile = null;
		IFile bucketFile = null;
		
		/* Creating persistent resources. */
		
		try {
			workflowFile = project.getFile("workflow.irs");
			workflowFile.create(workflowSource, IResource.FORCE, null);
		} catch (CoreException e1) {
			Logger.handle(MessageCode.WORKFLOW_SAVE_FILE_PROBLEM, e1);
			return false;
		}
		try {
			resourcesFile = project.getFile(ResourcesPersistence.DEFINITION_FILE);
			resourcesFile.create(resourcesSource, IResource.FORCE, null);
		} catch (CoreException e1) {
			Logger.handle(MessageCode.RESOURCES_SAVE_FILE_PROBLEM, e1);
			return false;
		}
		try {
			bucketFile = project.getFile(BucketPersistence.FILE);
			bucketFile.create(bucketSource, IResource.FORCE, null);
		} catch (CoreException e1) {
			Logger.handle(MessageCode.BUCKET_SAVE_FILE_PROBLEM, e1);
			return false;
		}
		
		/* Resources created. Preparing editor inputs for editors. */
		
		FileEditorInput workflowEditorInput = new FileEditorInput(workflowFile);
		FileEditorInput resourcesEditorInput = new FileEditorInput(resourcesFile);
		
		IWorkbench workbench = PlatformUI.getWorkbench();
		
		IEditorDescriptor workflowDesc = workbench.getEditorRegistry().getDefaultEditor(workflowFile.getName());
		IEditorDescriptor resourcesDesc = workbench.getEditorRegistry().getDefaultEditor(resourcesFile.getName());
		
		IWorkbenchPage page = workbench.getActiveWorkbenchWindow().getActivePage();
		
		/* Opening editors. */
		
		try {
			page.openEditor(resourcesEditorInput, resourcesDesc.getId());
		} catch (PartInitException e) {
			Logger.handle(MessageCode.EDITOR_OPEN_PROBLEM, e, resourcesDesc.getId(), resourcesEditorInput.getName());
			return false;
		}
		try {
			page.openEditor(workflowEditorInput, workflowDesc.getId());
		} catch (PartInitException e) {
			Logger.handle(MessageCode.EDITOR_OPEN_PROBLEM, e, workflowDesc.getId(), workflowEditorInput.getName());
			return false;
		}

		/* Editors opened. */
		
		return true;
	}
	
	private IProject createProject() {
		IWorkspaceRoot rootWorkspace = ResourcesPlugin.getWorkspace().getRoot();
		IProject project = rootWorkspace.getProject(newProjectModel.projectName);
		
		try {
			project.create(new NullProgressMonitor());
			project.open(new NullProgressMonitor());
		} catch (CoreException e1) {
			Logger.handle(MessageCode.WORKFLOW_CREATE_PROJECT_PROBLEM, e1);
			return null;
		}
		
		return project;
	}
	
	public InputStream createWorkflowAsStream() {
		IRSWorkflow workflow = createNewWorkflow();
		
		IPersistence<IRSWorkflow> manager = PersistenceAdapter.getManager(IRSWorkflow.class);
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		
		try {
			manager.writeToStream(workflow, baos);
		} catch (Exception ex) {
			Logger.handle(MessageCode.WORKFLOW_SAVE_SERIALIZE_PROBLEM, ex);
			return null;
		}
		
		InputStream stream = new ByteArrayInputStream(baos.toByteArray());
		return stream;
	}
	
	private IRSWorkflow createNewWorkflow() {
		IRSWorkflow workflow = new IRSWorkflow();

		workflow.setRootPlace(new IRSPlace(workflow.getIdManager()));
		workflow.getRootPlace().refine(Refinement.SEQUENCE);
		workflow.getRootPlace().setExpanded(true);
		//new StructuralLayout(workflow.getRootPlace().getChildren()).layout();
		//workflow.getRootPlace().getChildren().get(0).setPosition(new Position(300, 50));
		//workflow.getRootPlace().getChildren().get(1).setPosition(new Position(300, 250));
		//workflow.getRootPlace().getChildren().get(2).setPosition(new Position(300, 450));
		
		return workflow;
	}

	public InputStream createResourcesAsStream() {
		Resources resources = new Resources();
		IPersistence<Resources> manager = PersistenceAdapter.getManager(Resources.class);
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		
		try {
			manager.writeToStream(resources, baos);
		} catch (Exception ex) {
			Logger.handle(MessageCode.RESOURCES_SAVE_SERIALIZE_PROBLEM, ex);
			return null;
		}
		
		InputStream stream = new ByteArrayInputStream(baos.toByteArray());
		return stream;
	}

	public InputStream createRolesAsStream() {
		Roles roles = new Roles();
		IPersistence<Roles> manager = PersistenceAdapter.getManager(Roles.class);
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		
		try {
			manager.writeToStream(roles, baos);
		} catch (Exception ex) {
			Logger.handle(MessageCode.ROLES_SAVE_SERIALIZE_PROBLEM, ex);
			return null;
		}
		
		InputStream stream = new ByteArrayInputStream(baos.toByteArray());
		return stream;
	}

	public InputStream createBucketAsStream() {
		Bucket bucket = new Bucket();
		IPersistence<Bucket> manager = PersistenceAdapter.getManager(Bucket.class);
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		
		try {
			manager.writeToStream(bucket, baos);
		} catch (Exception ex) {
			Logger.handle(MessageCode.BUCKET_SAVE_SERIALIZE_PROBLEM, ex);
			return null;
		}
		
		InputStream stream = new ByteArrayInputStream(baos.toByteArray());
		return stream;
	}
}
